#pragma once
#include <iostream>
using namespace std;
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include "Err.hpp"
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstdlib>
#include <functional>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include"myLog.hpp"
static const uint16_t default_port = 8080;
static const int backlog = 32;
using func_t = function<string(const string &)>;

class tcp_server;
class ThreadData
{
public:
    ThreadData (int fd, string cilientIp, uint16_t cilientPort, tcp_server *cur)
        : sock(fd), clientip(cilientIp), clientport(cilientPort), current(cur)
    {
    }
public:
    int sock;
    string clientip;
    uint16_t clientport;
    tcp_server *current;
};
    
class tcp_server
{
public:
    tcp_server(func_t fuc, uint16_t port = default_port)
        : port_(port), fuc_(fuc)
    {
    }
    ~tcp_server()
    {
    }
    void Init()
    {
        listenSock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenSock_ < 0)
        {
            //cerr << "创建套接字失败：" << strerror(errno) << endl;
            logMessge(FATAL,"创建套接字失败，错误码：%d ,错误原因：%s",errno,strerror(errno));
            exit(SOCK_ERR);
        }
        struct sockaddr_in local;
        bzero(&local, sizeof(local));

        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = INADDR_ANY;
        if (bind(listenSock_, (sockaddr *)&local, sizeof(local)) < 0)
        {
            //cerr << "绑定失败：" << strerror(errno) << endl;
            logMessge(FATAL,"绑定失败，错误码：%d ,错误原因：%s",errno,strerror(errno));

            exit(BIND_ERR);
        }
        if (listen(listenSock_, backlog) < 0)
        {
            logMessge(FATAL,"绑定失败，错误码：%d ,错误原因：%s",errno,strerror(errno));
            exit(LISTEN_ERR);
        }
        logMessge(INFO,"准备就绪，错误码：%d ",errno);

    }

    void Start()
    {
        while (1)
        {
            struct sockaddr_in cilient;
            bzero(&cilient, sizeof(cilient));
            socklen_t len = sizeof(cilient);
            int sock = accept(listenSock_, (sockaddr *)&cilient, &len);
            if (sock < 0)
            {
                //cerr << "接收失败：" << strerror(errno) << endl;
                logMessge(WARING,"接收失败，错误码：%d ,错误原因：%s",errno,strerror(errno));

                continue;
            }
            string cilientIp = inet_ntoa(cilient.sin_addr);
            uint16_t cilientPort = ntohs(cilient.sin_port);
            logMessge(INFO,"连接成功！from %d to %d ",listenSock_,sock);
            
            // cout << "连接成功！"
            //      << " from " << listenSock_ << " to " << sock << endl;
            
            // pid_t pid = fork();
            // if (0 == pid)
            // {
            //     service(sock, cilientIp, cilientPort);
            // }
            // else if(0<pid)
            // {
            //     close(sock);
            //     continue;
            // }
            // signal(SIGCHLD,SIG_IGN);
            // close(sock);
            pthread_t tid;
            ThreadData *arg = new ThreadData(sock, cilientIp, cilientPort, this);
            pthread_create(&tid, nullptr, pthreadRoutine, arg);
            //Task(sock)

        }
    }


    static void *pthreadRoutine(void *arg)
    {
        pthread_detach(pthread_self());
        ThreadData *client = static_cast<ThreadData *>(arg);
        client->current ->service(client->sock , client->clientip, client->clientport);
        delete client;
        return nullptr;
    }
    void service(int fd, string &cilientIp, uint16_t cilientPort)
    {
        string who = cilientIp + '-' + to_string(cilientPort);
        char buf[1024];
        while (1)
        {
            char buf[1024];
            ssize_t s = read(fd, buf, sizeof(buf) - 1);
            if (s > 0)
            {
                buf[s] = 0;
                string res = fuc_(buf);
                logMessge(INFO,"%s # %s",who.c_str(),res.c_str());
                write(fd, res.c_str(), res.size());
            }
            else if (0 == s)
            {
                close(fd);
                logMessge(INFO,"%s 退出了，我也要退出！",who.c_str());

                //cout << who << " 退出了，我也要退出！\n";
                break;
            }
            else
            {
                cout << "读取失败：" << strerror(errno) << endl;
                exit(READ_ERR);
            }
        }
    }

private:
    uint16_t port_;
    int listenSock_;
    func_t fuc_;
};